﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace GBSHouse.UptimeRobot {
	public class UptimeRobotAPI {

		private string _key = String.Empty;

		public UptimeRobotAPI(string key) {
			_key = key;
		}

		#region Monitors

		/// <summary>
		/// Gets the monitors.
		/// </summary>
		/// <returns></returns>
		public List<UptimeRobotMonitor> GetMonitors() {
			return GetMonitors(new int[0], 0, false, false);
		}

		/// <summary>
		/// Gets the monitors.
		/// </summary>
		/// <param name="logs">if set to <c>true</c> [logs].</param>
		/// <returns></returns>
		public List<UptimeRobotMonitor> GetMonitors(bool logs) {
			return GetMonitors(new int[0], 0, logs, false);
		}

		/// <summary>
		/// Gets the monitors.
		/// </summary>
		/// <param name="monitors">The monitors.</param>
		/// <param name="customUptimeRatio">The custom uptime ratio.</param>
		/// <param name="logs">if set to <c>true</c> [logs].</param>
		/// <param name="showMonitorAlertContacts">if set to <c>true</c> [show monitor alert contacts].</param>
		/// <returns></returns>
		public List<UptimeRobotMonitor> GetMonitors(int[] monitors, int customUptimeRatio, bool logs, bool showMonitorAlertContacts) {
			try {
				using (WebClient client = new WebClient()) {
					Dictionary<string, string> dict = new Dictionary<string, string>();
					if(monitors.Length > 0)
						dict.Add("monitors", String.Join("-", monitors.Select(o => o.ToString()).ToArray()));
					if(customUptimeRatio > 0)
						dict.Add("customUptimeRatio", customUptimeRatio.ToString());
					dict.Add("logs", logs ? "1" : "0");
					dict.Add("showMonitorAlertContacts", showMonitorAlertContacts ? "1" : "0");
					string json = client.DownloadString(GetUrl("getMonitors", dict));

					if(!String.IsNullOrEmpty(json))
						json = json.Replace("\"alertcontact\"", "\"monitoralertcontact\"");

					var response = Deserialize<UptimeRobotMonitorCollectionResponse>(json);
					return response.MonitorList;
				}
			} catch {
				return new List<UptimeRobotMonitor>();
			}
		}

		/// <summary>
		/// Gets the monitor.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public UptimeRobotMonitor GetMonitor(int id) {
			try {
				using (WebClient client = new WebClient()) {
					Dictionary<string, string> dict = new Dictionary<string, string>();
					dict.Add("monitors", id.ToString());
					string json = client.DownloadString(GetUrl("getMonitors", dict));
					var response = Deserialize<UptimeRobotMonitorCollectionResponse>(json);
					if (response.MonitorList.Count > 0)
						return response.MonitorList.First();
					return null;
				}
			} catch {
				return null;
			}
		}

		/// <summary>
		/// Creates the HTTP monitor.
		/// </summary>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <param name="name">The name.</param>
		/// <param name="value">The value.</param>
		/// <param name="contacts">The contacts.</param>
		/// <returns></returns>
		public UptimeRobotMonitorResponse CreateHTTPMonitor(string username, string password, string name, Uri value, int[] contacts) {
			return CreateMonitor(UptimeRobotMonitorType.HTTP, UptimeRobotMonitorSubType.Unknown, null, UptimeRobotMonitorKeywordType.NotExists, null, username, password, name, value.ToString(), contacts);
		}

		/// <summary>
		/// Creates the keyword monitor.
		/// </summary>
		/// <param name="keywordType">Type of the keyword.</param>
		/// <param name="keyword">The keyword.</param>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <param name="name">The name.</param>
		/// <param name="value">The value.</param>
		/// <param name="contacts">The contacts.</param>
		/// <returns></returns>
		public UptimeRobotMonitorResponse CreateKeywordMonitor(UptimeRobotMonitorKeywordType keywordType, string keyword, string username, string password, string name, Uri value, int[] contacts) {
			return CreateMonitor(UptimeRobotMonitorType.Keyword, UptimeRobotMonitorSubType.Unknown, null, keywordType, keyword, username, password, name, value.ToString(), contacts);
		}

		/// <summary>
		/// Creates the ping monitor.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="value">The value.</param>
		/// <param name="contacts">The contacts.</param>
		/// <returns></returns>
		public UptimeRobotMonitorResponse CreatePingMonitor(string name, IPAddress value, int[] contacts) {
			return CreateMonitor(UptimeRobotMonitorType.Ping, UptimeRobotMonitorSubType.Unknown, null, UptimeRobotMonitorKeywordType.NotExists, null, null, null, name, value.ToString(), contacts);
		}

		/// <summary>
		/// Creates the port monitor.
		/// </summary>
		/// <param name="subtype">The subtype.</param>
		/// <param name="port">The port.</param>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <param name="name">The name.</param>
		/// <param name="value">The value.</param>
		/// <param name="contacts">The contacts.</param>
		/// <returns></returns>
		public UptimeRobotMonitorResponse CreatePortMonitor(UptimeRobotMonitorSubType subtype, int port, string username, string password, string name, IPAddress value, int[] contacts) {
			return CreateMonitor(UptimeRobotMonitorType.Port, subtype, port, UptimeRobotMonitorKeywordType.NotExists, null, username, password, name, value.ToString(), contacts);
		}

		/// <summary>
		/// Creates the monitor.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="subtype">The subtype.</param>
		/// <param name="port">The port.</param>
		/// <param name="keywordType">Type of the keyword.</param>
		/// <param name="keyword">The keyword.</param>
		/// <param name="username">The username.</param>
		/// <param name="password">The password.</param>
		/// <param name="name">The name.</param>
		/// <param name="value">The value.</param>
		/// <param name="contacts">The contacts.</param>
		/// <returns></returns>
		public UptimeRobotMonitorResponse CreateMonitor(UptimeRobotMonitorType type, UptimeRobotMonitorSubType subtype, int? port, UptimeRobotMonitorKeywordType keywordType, string keyword, string username, string password, string name, string value, int[] contacts) {
			try {
				using (WebClient client = new WebClient()) {
					Dictionary<string, string> dict = new Dictionary<string, string>();
					dict.Add("monitorType", ((int)type).ToString());
					dict.Add("monitorFriendlyName", name);
					dict.Add("monitorURL", value);
					
					if(contacts.Length > 0)
						dict.Add("monitorAlertContacts", String.Join("-", contacts.Select(o => o.ToString()).ToArray()));

					if (type == UptimeRobotMonitorType.Keyword && !String.IsNullOrEmpty(keyword)) {
						dict.Add("monitorKeywordType", ((int)keywordType).ToString());
						dict.Add("monitorKeywordValue", keyword);
					}

					if (type == UptimeRobotMonitorType.Port && subtype != UptimeRobotMonitorSubType.Unknown && port.HasValue) {
						dict.Add("monitorSubType", ((int)subtype).ToString());
						dict.Add("monitorPort", port.Value.ToString());
					}

					if (!String.IsNullOrEmpty(username))
						dict.Add("monitorHTTPUsername", username);

					if (!String.IsNullOrEmpty(password))
						dict.Add("monitorHTTPPassword", password);

					string json = client.DownloadString(GetUrl("newMonitor", dict));
					return Deserialize<UptimeRobotMonitorResponse>(json);
				}
			} catch {
				return null;
			}
		}

		public UptimeRobotMonitorResponse UpdateMonitor(int id, string value, int[] contacts) {
			try {
				using (WebClient client = new WebClient()) {
					var monitor = this.GetMonitor(id);
					if (monitor != null) {
						Dictionary<string, string> dict = new Dictionary<string, string>();
						dict.Add("monitorID", id.ToString());
						dict.Add("monitorURL", value);
						//dict.Add("monitorFriendlyName", monitor.Name);
						if(contacts.Length > 0)
							dict.Add("monitorAlertContacts", String.Join("-", contacts));
						string json = client.DownloadString(GetUrl("editMonitor", dict));
						int monitorID = 0;
						if (json.StartsWith("\"id\"") && Int32.TryParse(json.Replace("\"id\":", "").Replace("\"", ""), out monitorID))
							return new UptimeRobotMonitorResponse() { Status = "ok", MonitorID = monitorID };
						return Deserialize<UptimeRobotMonitorResponse>(json);
					}
					return null;
				}
			} catch {
				return null;
			}
		}

		/// <summary>
		/// Deletes the monitor.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public UptimeRobotMonitorResponse DeleteMonitor(int id) {
			try {
				using (WebClient client = new WebClient()) {
					Dictionary<string, string> dict = new Dictionary<string, string>();
					dict.Add("monitorID", id.ToString());
					string json = client.DownloadString(GetUrl("deleteMonitor", dict));
					return Deserialize<UptimeRobotMonitorResponse>(json);
				}
			} catch {
				return null;
			}
		}

		#endregion

		#region Contacts

		/// <summary>
		/// Verifies the account.
		/// </summary>
		/// <returns></returns>
		public bool VerifyAccount() {
			try {
				using (WebClient client = new WebClient()) {
					string json = client.DownloadString(GetUrl("getAlertContacts"));
					var response = Deserialize<UptimeRobotContactCollectionResponse>(json);
					return response.Success;
				}
			} catch {
				return false;
			}
		}

		/// <summary>
		/// Gets the contacts.
		/// </summary>
		/// <returns></returns>
		public List<UptimeRobotContact> GetContacts() {
			try {
				using (WebClient client = new WebClient()) {
					string json = client.DownloadString(GetUrl("getAlertContacts"));
					var response = Deserialize<UptimeRobotContactCollectionResponse>(json);
					return response.ContactList;
				}
			} catch {
				return new List<UptimeRobotContact>();
			}
		}

		/// <summary>
		/// Gets the contact.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public UptimeRobotContact GetContact(int id) {
			try {
				using (WebClient client = new WebClient()) {
					Dictionary<string, string> dict = new Dictionary<string, string>();
					dict.Add("alertcontacts", id.ToString());
					string json = client.DownloadString(GetUrl("getAlertContacts", dict));
					var response = Deserialize<UptimeRobotContactCollectionResponse>(json);
					if(response.ContactList.Count > 0)
						return response.ContactList.First();
					return null;
				}
			} catch {
				return null;
			}
		}

		/// <summary>
		/// Creates the contact.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="value">The value.</param>
		/// <returns></returns>
		public UptimeRobotContactResponse CreateContact(UptimeRobotContactType type, string value) {
			try {
				using (WebClient client = new WebClient()) {
					Dictionary<string, string> dict = new Dictionary<string, string>();
					dict.Add("alertContactType", ((int)type).ToString());
					dict.Add("alertContactValue", value);
					string json = client.DownloadString(GetUrl("newAlertContact", dict));
					return Deserialize<UptimeRobotContactResponse>(json);
				}
			} catch {
				return null;
			}
		}

		/// <summary>
		/// Deletes the contact.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public UptimeRobotContactResponse DeleteContact(int id) {
			try {
				using (WebClient client = new WebClient()) {
					Dictionary<string, string> dict = new Dictionary<string, string>();
					dict.Add("alertContactID", id.ToString());
					string json = client.DownloadString(GetUrl("deleteAlertContact", dict));
					return Deserialize<UptimeRobotContactResponse>(json);
				}
			} catch {
				return null;
			}
		}

		#endregion

		#region Private

		/// <summary>
		/// Gets the URL.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <returns></returns>
		private string GetUrl(string name) {
			return String.Format("http://api.uptimerobot.com/{0}?apiKey={1}&format=json&noJsonCallback=1", name, _key);
		}

		/// <summary>
		/// Gets the URL.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="parameters">The parameters.</param>
		/// <returns></returns>
		private string GetUrl(string name, Dictionary<string, string> parameters) {
			string p = String.Join("&", parameters.Select(o => String.Format("{0}={1}", o.Key, o.Value)).ToArray());
			return String.Format("http://api.uptimerobot.com/{0}?apiKey={1}&format=json&noJsonCallback=1&{2}", name, _key, p);
		}

		/// <summary>
		/// Serializes the specified item.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="item">The item.</param>
		/// <returns></returns>
		private string Serialize<T>(T item) {
			return JsonConvert.SerializeObject(item);
		}

		/// <summary>
		/// Deserializes the specified text.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="text">The text.</param>
		/// <returns></returns>
		private T Deserialize<T>(string text) {
			return JsonConvert.DeserializeObject<T>(text);
		}

		#endregion
	}
}
